package com.crape.common.tools;

/**
 * @author ChenKai
 * DES加密算法
 */
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * DES加密的，文件中共有两个方法,加密、解密
 */
public class DESEncoder implements IDESEncoder {

    private static final DESEncoder instance  = new DESEncoder();

    private String                  Key       = "des@carepsy.com";
    private String                  IV        = "75623298";

    private String                  Algorithm = "DES";
    private SecretKey               deskey;
    private IvParameterSpec         iv;
    private Cipher                  cipher;

    /**
     * 系统默认编码器, 实例 默认Key = des@carepsy.com ; IV = 475623298
     * @return
     */
    public static DESEncoder getInstance() {
        return instance;
    }

    /**
     * 用户自定义编码器
     * @param Key
     * @param IV
     * @return
     */
    public static DESEncoder getMyInstance(String Key, String IV) {
        return new DESEncoder(Key, IV);
    }

    /**
     * 初始化 DESEncoder
     */
    private DESEncoder(){
        init();
    }

    /**
     * 初始化 DESEncoder 实例 设置新的Key和IV
     * 
     * @param Key
     * @param IV
     */
    private DESEncoder(String Key, String IV){
        this.Key = Key;
        this.IV = IV;
        init();
    }

    /**
     * 对 String str 进行加密
     * 
     * @param str
     * @return 返回加密后的 String
     */
    public String Encode(String str) {
        byte[] encryptorByte = null;
        String byteToString = null;
        try {
            encryptorByte = this.encryptorBase64Bytes(str);
            byteToString = this.base64BytesToString(encryptorByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return byteToString;
    }

    /**
     * 对 String base64str 进行解密
     * 
     * @param base64str
     * @return 返回解密后的 String
     */
    public String Decode(String base64str) {
        String decryptorString = null;
        byte[] stringToByte = null;
        try {
            stringToByte = this.base64StringToBytes(base64str);
            decryptorString = this.decryptorString(stringToByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decryptorString;
    }

    /**
     * 初始化 DESEncoder 加密算法的一些参数
     */
    private void init() {
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        try {
            cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            DESKeySpec desKeySpec = new DESKeySpec(Key.getBytes("ASCII"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(Algorithm);
            deskey = keyFactory.generateSecret(desKeySpec);

            iv = new IvParameterSpec(IV.getBytes("ASCII"));

        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        } catch (NoSuchPaddingException ex) {
            ex.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将字符串转化为UTF-8数组并进行加密
     * 
     * @param inputStr
     * @return byte[]
     * @throws Exception
     */
    private byte[] encryptorBase64Bytes(String inputStr) throws Exception {
        cipher.init(Cipher.ENCRYPT_MODE, deskey, iv);
        byte[] dataSourceBytes = inputStr.getBytes("UTF-8");
        byte[] encryptorData = cipher.doFinal(dataSourceBytes);
        return encryptorData;
    }

    /**
     * 对 inputBytes 数组进行解密并转换为UTF-8型String
     * 
     * @param inputBytes 要解密的数据
     * @return 返回解密后的 String
     */
    private String decryptorString(byte[] inputBytes) throws Exception {
        cipher.init(Cipher.DECRYPT_MODE, deskey, iv);
        byte[] decryptorData = cipher.doFinal(inputBytes);
        String decryptorString = new String(decryptorData, "UTF-8");
        return decryptorString;
    }

    /**
     * 将byte数组转换为String
     * 
     * @param dataByte
     * @return
     */
    private String base64BytesToString(byte[] dataByte) {
        String returnStr = null;
        BASE64Encoder be = new BASE64Encoder();
        returnStr = be.encode(dataByte);
        return returnStr;
    }

    /**
     * 将String转换为byte数组
     * 
     * @param dataByte
     * @return
     * @throws Exception
     */
    private byte[] base64StringToBytes(String inputStr) throws Exception {
        BASE64Decoder bd = new BASE64Decoder();
        byte[] sorData = bd.decodeBuffer(inputStr);
        return sorData;
    }
}
